package adfc2.render3d.mesh;

import adfc2.Renderer3D;
import adfc2.render3d.IRenderable;
import adfc2.render3d.TextureReference;
import com.sun.opengl.util.BufferUtil;

import javax.media.opengl.GL;
import java.nio.DoubleBuffer;

/**
 * Примитив --- набор вершин (координаты, текстура, нормали)
 */
public class Primitive implements IRenderable {
    /**
     * тип (GL_LINES и т.п.)
     */
    public final int mode;
    /**
     * Цвет
     */
    public final double[] color;
    /**
     * число вершин
     */
    public final int size;
    /**
     * вершины
     */
    public final DoubleBuffer vbuf;
    /**
     * текстурные координаты
     */
    public final DoubleBuffer tbuf;
    /**
     * нормали
     */
    public final DoubleBuffer nbuf;
    /**
     * текстура
     */
    public final TextureReference texture;

    /**
     * @param mode     Режим рендера (GL_LINES и т.п.)
     * @param color    Цвет примитива (null - не менять)
     * @param vertices Массив 3D-координат вершин
     * @param texcoord Массив текстурных 2D-координат вершин. null если не нужна текстура
     * @param normals  Массив 3D-координат нормалей.
     * @param texture  Текстура (null если не нужна)
     */
    public Primitive(int mode, double[] color, double[] vertices, double[] texcoord, double[] normals, TextureReference texture) {
        this.mode = mode;
        if (color != null && color.length == 3) {
            this.color = new double[]{color[0], color[1], color[2], 1};
        } else {
            this.color = color;
        }
        this.size = vertices.length / 3;
        this.vbuf = BufferUtil.copyDoubleBuffer(DoubleBuffer.wrap(vertices));
        assert size * 3 == vbuf.limit() : "Vertex buffer size error";
        if (texture != null && texcoord != null) {
            this.tbuf = BufferUtil.copyDoubleBuffer(DoubleBuffer.wrap(texcoord));
            assert size * 2 == tbuf.limit() : "Texcoord buffer size error";
            this.texture = texture;
        } else {
            this.tbuf = null;
            this.texture = null;
        }
        this.nbuf = BufferUtil.copyDoubleBuffer(DoubleBuffer.wrap(normals));
        assert size * 3 == nbuf.limit() : "Normal buffer size error";
    }

    public void render(Renderer3D renderer) {
        GL gl = renderer.gl();
        renderer.ensureClientEnabled(GL.GL_VERTEX_ARRAY, true);
        renderer.ensureClientEnabled(GL.GL_NORMAL_ARRAY, true);
        if (color != null) gl.glColor4dv(color, 0);
        gl.glVertexPointer(3, GL.GL_DOUBLE, 0, vbuf);
        if (texture != null && texture != TextureReference.NO_TEXTURE) {
            renderer.ensureClientEnabled(GL.GL_TEXTURE_COORD_ARRAY, true);
            gl.glTexCoordPointer(2, GL.GL_DOUBLE, 0, tbuf);
            texture.activate(renderer);
        } else {
            renderer.ensureEnabled(GL.GL_TEXTURE_COORD_ARRAY, false);
            TextureReference.NO_TEXTURE.activate(renderer);
        }
        gl.glNormalPointer(GL.GL_DOUBLE, 0, nbuf);
        gl.glDrawArrays(mode, 0, size);
    }
}
